package pdm.traj.part;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import pdm.traj.entity.PartInfo;
import pdm.traj.entity.TrackPoint2;
import pdm.traj.entity.TrajQuery;
import pdm.traj.service.GeoService;

public abstract class PartPlan {
    public static final String TAG = "PartPlan";
    protected GeoService geoService;
	protected List<PartInfo> partInfo;
    protected List<String> ips;
	protected List<String> ports;
	/**
	 * 节点总数
	 */
    protected int nodeNum = -1;
//    protected Map<Integer, PartInfo> indexPartInfoMap;
    protected Map<Integer, List<String>> piSidMap;//partinfo sid map

    /**
     * 查询一个trackpoint存在哪个节点
     * @param tp
     * @return
     */
	public abstract PartInfo getPartInfoByTP(TrackPoint2 tp);

    /**
     * 查询一个基站的信息存在哪些节点
     * @param sid
     * @return
     */
    public abstract List<PartInfo> getPartInfoBySid(String sid);

    /**
     * 查询一个给定查询的结果存在哪些节点
     * @param query
     * @return
     */
	public abstract List<PartInfo> getPartInfoByQuery(TrajQuery query);

    public Integer getPIIndexByTP(TrackPoint2 tp) {
        return getPartInfoIndex(getPartInfoByTP(tp));
    }

    public abstract String getName();
    
    protected abstract void initPlan();
    
    public String getKeyPrefix() {
		return TAG + "_" + getName();
    }

    public List<String> getSidsByPartInfoIndex(int index) {
        if (index >= 0 && index < nodeNum) {
             return piSidMap.get(index);
        }
        return null;
    }

    public int getPartInfoIndexByTP(TrackPoint2 tp) {
        return getPartInfoIndex(getPartInfoByTP(tp));
    }

    public List<Integer> getPartInfoIndexBySid(String sid) {
        List<Integer> result = new ArrayList<Integer>();
        List<PartInfo> partInfos = getPartInfoBySid(sid);
        for (PartInfo partInfo1 : partInfos) {
            result.add(getPartInfoIndex(partInfo1));
        }
        return result;
    }

    public int getPartInfoIndex(PartInfo partInfo1) {
        for (int i = 0; i < nodeNum; i++) {
            if (partInfo.get(i).equals(partInfo1)) {
                return i;
            }
        }
        return -1;
    }
    
    /**
     * 用索引获得分片信息
     * @param index
     * @return
     */
    public PartInfo getPartInfo(int index) {
        if (index >= 0&& index < partInfo.size()) {
            return partInfo.get(index);
        } else {
            return null;
        }
    }

    /**
     * init part service
     */
	public void init() {
        // check
        if (ips == null || ports == null) {
            System.err.println(TAG + ": init(): ips or ports null value");
            return;
        }
        if (ips.size() == 0 || ports.size() == 0) {
            System.err.println(TAG + ": init(): ips or ports no entry");
            return;
        }
        if (ips.size() != ports.size()) {
            System.err.println(TAG + ": init(): ips and ports size not equal");
            return;
        }
		partInfo = new ArrayList<PartInfo>();
        nodeNum = ips.size();
        for (int i = 0; i < nodeNum; i++) {
            PartInfo pi = new PartInfo(ips.get(i), ports.get(i));
            partInfo.add(pi);
        }
        initPlan();
        initPiSidMap();
	}

    private void initPiSidMap() {
        piSidMap = new HashMap<Integer, List<String>>();
        List<String> allSid = geoService.getAllSids();
        for (int i = 0; i < partInfo.size(); i++) {
            piSidMap.put(i, new ArrayList<String>());
        }
        for (String sid : allSid) {
            List<Integer> indices = getPartInfoIndexBySid(sid);
            for (Integer index : indices) {
                piSidMap.get(index).add(sid);
            }
        }
    }
	
	public List<PartInfo> getAllPartInfo() {
		return partInfo;
	}

    public void setGeoService(GeoService geoService) {
        this.geoService = geoService;
    }

    public Map<Integer, List<String>> getPiSidMap() {
        return piSidMap;
    }

    public List<String> getIps() {
        return ips;
    }

    public void setIps(List<String> ips) {
        this.ips = ips;
    }

    public List<String> getPorts() {
        return ports;
    }

    public void setPorts(List<String> ports) {
        this.ports = ports;
    }

    public int getNodeNum() {
        return nodeNum;
    }

}
